Inside Macintosh: Memory

Previous | Chapter Top | Chapter Contents | Next

Extending an Application's Memory

Rather than using your application's 'SIZE' resource to specify a preferred partition size that is large enough to contain the largest possible application heap, you should specify a smaller but adequate partition size. When you need more memory for temporary use, you can use a set of Memory Manager routines for the allocation of temporary memory.

By using the routines for allocating temporary memory, your application can request some additional memory for occasional short-term needs. For example, the Finder uses these temporary-memory routines to secure buffer space for use during file copy operations. Any available memory (that is, memory currently unallocated to any application's partition) is dedicated to this purpose. The Finder releases this memory as soon as the copy is completed, thus making the memory available to other applications or to the Operating System for launching new applications.

Because the requested amount of memory might not be available, you cannot be sure that every request for temporary memory will be honored. Thus, you should make sure that your application will work even if your request for temporary memory is denied. For example, if the Finder cannot allocate a large temporary copy buffer, it uses a reserved small copy buffer from within its own heap zone, prolonging the copying but performing it nonetheless.

Temporary memory is taken from RAM that is reserved for (but not yet used by) other applications. Thus, if you use too much temporary memory or hold temporary memory for long periods of time, you might prevent the user from being able to launch other applications. In certain circumstances, however, you can hold temporary memory indefinitely. For example, if the temporary memory is used for open files and the user can free that memory simply by closing those files, it is safe to hold onto that memory as long as necessary.

Temporary memory is tracked (or monitored) for each application, and so you must use it only for code that is running on an application's behalf. Moreover, the Operating System frees all temporary memory allocated to an application when the application quits or crashes. As a result, you should not use temporary memory for VBL tasks, Time Manager tasks, or other procedures that should continue to be executed after your application quits. Similarly, it is wise not to use temporary memory for an interprocess buffer (that is, a buffer whose address is passed to another application in a high-level event) because the originating application could crash, quit, or be terminated, thereby causing the temporary memory to be released before (or even while) the receiving application uses that memory.

Although you can usually perform ordinary Memory Manager operations on temporary memory, there are two restrictions. First, you must never lock temporary memory across calls to GetNextEvent or WaitNextEvent . Second, although you can determine the zone from which temporary memory is generated (using the HandleZone function), you should not use this information to make new blocks or perform heap operations on your own.

Allocating Temporary Memory

You can request a block of memory for temporary use by calling the Memory Manager's TempNewHandle function. This function attempts to allocate a new relocatable block of the specified size for temporary use. For example, to request a block that is one-quarter megabyte in size, you might issue this command:

myHandle := TempNewHandle($40000, myErr);               {request temp memory}

If the routine succeeds, it returns a handle to the block of memory. The block of memory returned by a successful call to TempNewHandle is initially unlocked. If an error occurs and TempNewHandle fails, it returns a NIL handle. You should always check for NIL handles before using any temporary memory. If you detect a NIL handle, the second parameter (in this example, myErr ) contains the result code from the function.

Instead of asking for a specific amount of memory and then checking the returned handle to find out whether it was allocated, you might prefer to determine beforehand how much temporary memory is available. There are two functions that return information on the amount of free memory available for temporary allocation. The first is the TempFreeMem function, which you can use as follows:

memFree := TempFreeMem;             {find amount of free temporary memory}

The result is a long integer containing the amount, in bytes, of free memory available for temporary allocation. It usually isn't possible to allocate a block of this size because of fragmentation. Consequently, you'll probably want to use the second function, TempMaxMem , to determine the size of the largest contiguous block of space available. To allocate that block, you can write

mySize := TempMaxMem(grow);
myHandle := TempNewHandle(mySize, myErr);

The TempMaxMem function returns the size, in bytes, of the largest contiguous free block available for temporary allocation. (The TempMaxMem function is analogous to the MaxMem function.) The grow parameter is a variable parameter of type Size ; after the function returns, it always contains 0, because the temporary memory does not come from the application's heap. Even when you use TempMaxMem to determine the size of the available memory, you should check that the handle returned by TempNewHandle is not NIL .

Determining the Features of Temporary Memory

Only computers running system software version 7.0 and later can use temporary memory as described in this chapter. For this reason, you should always check that the routines are available and that they have the features you require before calling them.

The temporary-memory routines are available in some earlier system software versions when MultiFinder is running. However, the handles to blocks of temporary memory are neither tracked nor real.

The Gestalt function includes a selector to determine whether the temporary-memory routines are present in the operating environment and, if they are, whether the temporary-memory handles are tracked and whether they are real. If temporary-memory handles are not tracked, you must release temporary memory before your next call to GetNextEvent or WaitNextEvent . If temporary-memory handles are not real, then you cannot use normal Memory Manager routines such as HLock to manipulate them.

To determine whether the temporary-memory routines are implemented, you can check the value returned by the TempMemCallsAvailable function, defined in Listing 3 .

Listing 3 Determining whether temporary-memory routines are available

FUNCTION TempMemCallsAvailable: Boolean;
VAR
    myErr:      OSErr;                      {Gestalt result code}
    myRsp:      LongInt;                    {response returned by Gestalt}
BEGIN
    TempMemCallsAvailable := FALSE;
    myErr := Gestalt(gestaltOSAttr, myRsp);
    IF myErr <> noErr THEN          
        DoError(myErr)                  {Gestalt failed}
    ELSE                                {check bit for temp mem support}
        TempMemCallsAvailable :=
                BAND(myRsp, gestaltTempMemSupport) <> 0;
END;

You can use similar code to determine whether temporary-memory handles are real and whether the temporary memory is tracked.


© 1997 Apple Computer, Inc.

Previous | Chapter Top | Chapter Contents | Next